install -m 0755 -s pig2vcd /usr/local/bin
install -m 0755 -s pigpiod /usr/local/bin
install -m 0755 -s pigs /usr/local/bin
- python2 setup.py install
- python3 setup.py install
+ if which python2; then python2 setup.py install; fi
+ if which python3; then python3 setup.py install; fi
install -m 0755 -d /usr/local/man/man1
install -m 0644 *.1 /usr/local/man/man1
install -m 0755 -d /usr/local/man/man3
rm -f /usr/local/bin/pig2vcd
rm -f /usr/local/bin/pigpiod
rm -f /usr/local/bin/pigs
- echo removing python2 files
- python2 setup.py install --record /tmp/pigpio >/dev/null
- xargs rm -f < /tmp/pigpio >/dev/null
- echo removing python3 files
- python3 setup.py install --record /tmp/pigpio >/dev/null
- xargs rm -f < /tmp/pigpio >/dev/null
+ if which python2; then python2 setup.py install --record /tmp/pigpio >/dev/null; xargs rm -f < /tmp/pigpio >/dev/null; fi
+ if which python3; then python3 setup.py install --record /tmp/pigpio >/dev/null; xargs rm -f < /tmp/pigpio >/dev/null; fi
rm -f /usr/local/man/man1/pig*.1
rm -f /usr/local/man/man3/pig*.3
ldconfig
*/
/*
-This version is for pigpio version 37+
+This version is for pigpio version 38+
*/
#include <stdio.h>
{PI_CMD_CF1, "CF1", 195, 2}, // gpioCustom1
{PI_CMD_CF2, "CF2", 195, 6}, // gpioCustom2
+ {PI_CMD_CGI, "CGI", 101, 4}, // gpioCfgGetInternals
+ {PI_CMD_CSI, "CSI", 111, 1}, // gpioCfgSetInternals
+
{PI_CMD_GDC, "GDC", 112, 2}, // gpioGetPWMdutycycle
{PI_CMD_GPW, "GPW", 112, 2}, // gpioGetServoPulsewidth
CF1 ... Custom function 1\n\
CF2 ... Custom function 2\n\
\n\
+CGI Configuration get internals\n\
+CSI v Configuration set internals\n\
+\n\
GDC g Get PWM dutycycle for gpio\n\
GPW g Get servo pulsewidth for gpio\n\
\n\
{PI_BAD_HCLK_PASS , "need password to use hardware clock 1"},
{PI_HPWM_ILLEGAL , "illegal, PWM in use for main clock"},
{PI_BAD_DATABITS , "serial data bits not 1-32"},
+ {PI_BAD_STOPBITS , "serial (half) stop bits not 2-8"},
{PI_MSG_TOOBIG , "socket/pipe message too big"},
{PI_BAD_MALLOC_MODE , "bad memory allocation mode"},
{PI_TOO_MANY_SEGS , "too many I2C transaction segments"},
{PI_CHAIN_TOO_BIG , "chain is too long"},
{PI_DEPRECATED , "deprecated function removed"},
{PI_BAD_SER_INVERT , "bit bang serial invert not 0 or 1"},
+ {PI_BAD_EDGE , "bad ISR edge, not 1, 1, or 2"},
+ {PI_BAD_ISR_INIT , "bad ISR initialisation"},
+ {PI_BAD_FOREVER , "loop forever must be last chain command"},
};
switch (cmdInfo[idx].vt)
{
- case 101: /* BR1 BR2 H HELP HWVER
+ case 101: /* BR1 BR2 CGI H HELP HWVER
DCRA HALT INRA NO
PIGPV POPA PUSHA RET T TICK WVBSY WVCLR
WVCRE WVGO WVGOR WVHLT WVNEW
break;
- case 111: /* BC1 BC2 BS1 BS2
- ADD AND CMP DIV LDA LDAB MLT
+ case 111: /* ADD AND BC1 BC2 BS1 BS2
+ CMP CSI DIV LDA LDAB MLT
MOD OR RLA RRA STAB SUB WAIT XOR
One parameter, any value.
.br
.br
-seqno starts at 0 each time the handle is opened and then increments
-by one for each report.
+seqno: starts at 0 each time the handle is opened and then increments by one for each report.
.br
.br
-flags, if bit 5 is set then bits 0-4 of the flags indicate a gpio which
-has had a watchdog timeout.
+flags: two flags are defined, PI_NTFY_FLAGS_WDOG and PI_NTFY_FLAGS_ALIVE. If bit 5 is set (PI_NTFY_FLAGS_WDOG) then bits 0-4 of the flags indicate a gpio which has had a watchdog timeout; if bit 6 is set (PI_NTFY_FLAGS_ALIVE) this indicates a keep alive signal on the pipe/socket and is sent once a minute in the absence of other notification activity.
.br
.br
-tick is the number of microseconds since system boot.
+tick: the number of microseconds since system boot. It wraps around after 1h12m.
.br
.br
-level indicates the level of each gpio.
-
-.br
-
-.br
-pig2vcd takes these notifications and outputs a text format VCD.
+level: indicates the level of each gpio. If bit 1<<x is set then gpio x is high. pig2vcd takes these notifications and outputs a text format VCD.
.br
.br
.br
-gpioSetAlertFunc(4, aFunction);
+gpioSetAlertFunc(4F, aFunction);
.br
.EE
.br
See \fBgpioSetAlertFunc\fP for further details.
+.IP "\fBint gpioSetISRFunc(unsigned user_gpio, unsigned edge, int timeout, gpioISRFunc_t f)\fP"
+.IP "" 4
+Registers a function to be called (a callback) whenever the specified
+gpio interrupt occurs.
+
+.br
+
+.br
+
+.EX
+user_gpio: 0-31
+.br
+ edge: RISING_EDGE, FALLING_EDGE, or EITHER_EDGE
+.br
+ timeout: interrupt timeout in milliseconds (<=0 to cancel)
+.br
+ f: the callback function
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_EDGE,
+or PI_BAD_ISR_INIT.
+
+.br
+
+.br
+One function may be registered per gpio.
+
+.br
+
+.br
+The function is passed the gpio, the current level, and the
+current tick. The level will be PI_TIMEOUT if the optional
+interrupt timeout expires.
+
+.br
+
+.br
+The underlying Linux sysfs gpio interface is used to provide
+the interrupt services.
+
+.br
+
+.br
+The first time the function is called, with a non-NULL f, the
+gpio is exported, set to be an input, and set to interrupt
+on the given edge and timeout.
+
+.br
+
+.br
+Subsequent calls, with a non-NULL f, can vary one or more of the
+edge, timeout, or function.
+
+.br
+
+.br
+The ISR may be cancelled by passing a NULL f, in which case the
+gpio is unexported.
+
+.br
+
+.br
+The tick is that read at the time the process was informed of
+the interrupt. This will be a variable number of microseconds
+after the interrupt occurred. Typically the latency will be of
+the order of 50 microseconds. The latency is not guaranteed
+and will vary with system load.
+
+.br
+
+.br
+The level is that read at the time the process was informed of
+the interrupt, or PI_TIMEOUT if the optional interrupt timeout
+expired. It may not be the same as the expected edge as
+interrupts happening in rapid succession may be missed by the
+kernel (i.e. this mechanism can not be used to capture several
+interrupts only a few microseconds apart).
+
+.IP "\fBint gpioSetISRFuncEx(unsigned user_gpio, unsigned edge, int timeout, gpioISRFuncEx_t f, void *userdata)\fP"
+.IP "" 4
+Registers a function to be called (a callback) whenever the specified
+gpio interrupt occurs.
+
+.br
+
+.br
+
+.EX
+user_gpio: 0-31
+.br
+ edge: RISING_EDGE, FALLING_EDGE, or EITHER_EDGE
+.br
+ timeout: interrupt timeout in milliseconds (<=0 to cancel)
+.br
+ f: the callback function
+.br
+ userdata: pointer to arbitrary user data
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_EDGE,
+or PI_BAD_ISR_INIT.
+
+.br
+
+.br
+The function is passed the gpio, the current level, the
+current tick, and the userdata pointer.
+
+.br
+
+.br
+Only one of \fBgpioSetISRFunc\fP or \fBgpioSetISRFuncEx\fP can be
+registered per gpio.
+
+.br
+
+.br
+See \fBgpioSetISRFunc\fP for further details.
+
.IP "\fBint gpioNotifyOpen(void)\fP"
.IP "" 4
This function requests a free notification handle.
.br
.br
-Name Cmd & Data Meaning
+Name Cmd & Data Meaning
.br
-Loop Start 255 0 Identify start of a wave block
+Loop Start 255 0 Identify start of a wave block
.br
-Loop Repeat 255 1 x y loop x + y*256 times
+Loop Repeat 255 1 x y loop x + y*256 times
.br
-Delay 255 2 x y delay x + y*256 microseconds
+Delay 255 2 x y delay x + y*256 microseconds
.br
+Loop Forever 255 3 loop forever
+
+.br
+
+.br
+
+.br
+If present Loop Forever must be the last entry in the chain.
.br
Auto will use the mailbox method unless a larger than default buffer
size is requested with \fBgpioCfgBufferSize\fP.
-.IP "\fBint gpioCfgInternals(unsigned cfgWhat, int cfgVal)\fP"
+.IP "\fBint gpioCfgInternals(unsigned cfgWhat, unsigned cfgVal)\fP"
.IP "" 4
Used to tune internal settings.
.EE
+.IP "\fBuint32_t gpioCfgGetInternals(void)\fP"
+.IP "" 4
+This function returns the current library internal configuration
+settings.
+
+.IP "\fBint gpioCfgSetInternals(uint32_t cfgVal)\fP"
+.IP "" 4
+This function sets the current library internal configuration
+settings.
+
+.br
+
+.br
+
+.EX
+cfgVal: see source code
+.br
+
+.EE
+
.IP "\fBint gpioCustom1(unsigned arg1, unsigned arg2, char *argx, unsigned argc)\fP"
.IP "" 4
This function is available for user customisation.
.br
.EX
-#define PI_HW_CLK_MIN_FREQ 4689
+PI_HW_CLK_MIN_FREQ 4689
.br
-#define PI_HW_CLK_MAX_FREQ 250000000
+PI_HW_CLK_MAX_FREQ 250000000
.br
.EE
.br
.EX
-#define PI_MIN_WAVE_DATABITS 1
+PI_MIN_WAVE_DATABITS 1
.br
-#define PI_MAX_WAVE_DATABITS 32
+PI_MAX_WAVE_DATABITS 32
.br
.EE
.br
+.IP "\fBedge\fP: 0-2" 0
+The type of gpio edge to generate an intrrupt. See\fBgpioSetISRFunc\fP,
+and \fBgpioSetISRFuncEx\fP.
+
+.br
+
+.br
+
+.EX
+RISING_EDGE 0
+.br
+FALLING_EDGE 1
+.br
+EITHER_EDGE 2
+.br
+
+.EE
+
+.br
+
+.br
+
.IP "\fBf\fP" 0
.br
.br
+.IP "\fBgpioISRFunc_t\fP" 0
+
+.EX
+typedef void (*gpioISRFunc_t)
+.br
+ (int gpio, int level, uint32_t tick);
+.br
+
+.EE
+
+.br
+
+.br
+
+.IP "\fBgpioISRFuncEx_t\fP" 0
+
+.EX
+typedef void (*gpioISRFuncEx_t)
+.br
+ (int gpio, int level, uint32_t tick, void *userdata);
+.br
+
+.EE
+
+.br
+
+.br
+
.IP "\fBgpioPulse_t\fP" 0
.EX
.br
.EX
-#define PI_HW_PWM_RANGE 1000000
+PI_HW_PWM_RANGE 1000000
.br
.EE
.br
.EX
-#define PI_HW_PWM_MIN_FREQ 1
+PI_HW_PWM_MIN_FREQ 1
.br
-#define PI_HW_PWM_MAX_FREQ 125000000
+PI_HW_PWM_MAX_FREQ 125000000
.br
.EE
.br
.EX
-#define PI_MIN_WAVE_HALFSTOPBITS 2
+PI_MIN_WAVE_HALFSTOPBITS 2
.br
-#define PI_MAX_WAVE_HALFSTOPBITS 8
+PI_MAX_WAVE_HALFSTOPBITS 8
.br
.EE
.br
.IP "\fBtimeout\fP" 0
-A gpio watchdog timeout in milliseconds.
+A gpio level change timeout in milliseconds.
+
+.br
+
+.br
+\fBgpioSetWatchdog\fP
.EX
PI_MIN_WDOG_TIMEOUT 0
.br
+.br
+\fBgpioSetISRFunc\fP and \fBgpioSetISRFuncEx\fP
+
+.EX
+<=0 cancel timeout
+.br
+>0 timeout after specified milliseconds
+.br
+
+.EE
+
+.br
+
.br
.IP "\fBtimer\fP" 0
#define PI_CMD_SLRI 94
.br
+.br
+#define PI_CMD_CGI 95
+.br
+#define PI_CMD_CSI 96
+.br
+
.br
#define PI_CMD_NOIB 99
.br
.br
#define PI_BAD_SER_INVERT -121 // bit bang serial invert not 0 or 1
.br
+#define PI_BAD_EDGE -122 // bad ISR edge value, not 0-2
+.br
+#define PI_BAD_ISR_INIT -123 // bad ISR initialisation
+.br
+#define PI_BAD_FOREVER -124 // loop forever must be last chain command
+.br
.br
#define PI_PIGIF_ERR_0 -2000
#define PI_DEFAULT_MEM_ALLOC_MODE PI_MEM_ALLOC_AUTO
.br
+.br
+#define PI_DEFAULT_CFG_INTERNALS 0
+.br
+
.br
.EE
For more information, please refer to <http://unlicense.org/>
*/
-/* pigpio version 37 */
+/* pigpio version 38 */
/* include ------------------------------------------------------- */
{
callbk_t func;
unsigned ex;
- void * userdata;
- int timeout;
+ void *userdata;
+ int timeout;
uint32_t tick;
} gpioAlert_t;
+typedef struct
+{
+ unsigned gpio;
+ pthread_t *pth;
+ callbk_t func;
+ unsigned edge;
+ int timeout;
+ unsigned ex;
+ void *userdata;
+ int inited;
+} gpioISR_t;
+
typedef struct
{
callbk_t func;
unsigned ex;
- void * userdata;
+ void *userdata;
} gpioSignal_t;
typedef struct
{
callbk_t func;
unsigned ex;
- void * userdata;
+ void *userdata;
uint32_t bits;
} gpioGetSamples_t;
typedef struct
{
- callbk_t func;
- unsigned ex;
- void * userdata;
- unsigned id;
- unsigned running;
- unsigned millis;
+ callbk_t func;
+ unsigned ex;
+ void *userdata;
+ unsigned id;
+ unsigned running;
+ unsigned millis;
struct timespec nextTick;
- pthread_t pthId;
+ pthread_t pthId;
} gpioTimer_t;
typedef struct
uint32_t lastReportTick;
int fd;
int pipe;
+ int max_emits;
} gpioNotify_t;
typedef struct
typedef struct
{
- uint32_t startTick;
uint32_t alertTicks;
+ uint32_t lateTicks;
+ uint32_t moreToDo;
uint32_t diffTick[TICKSLOTS];
uint32_t cbTicks;
uint32_t cbCalls;
uint32_t numSamples;
uint32_t DMARestarts;
uint32_t dmaInitCbsCount;
+ uint32_t goodPipeWrite;
+ uint32_t shortPipeWrite;
+ uint32_t wouldBlockPipeWrite;
} gpioStats_t;
typedef struct
unsigned DMAsecondaryChannel;
unsigned socketPort;
unsigned ifFlags;
- int dbgLevel;
- unsigned showStats;
unsigned memAllocMode;
+ unsigned dbgLevel;
+ unsigned alertFreq;
+ uint32_t internals;
+ /*
+ 0-3: dbgLevel
+ 4-7: alertFreq
+ */
} gpioCfg_t;
typedef struct
static gpioAlert_t gpioAlert [PI_MAX_USER_GPIO+1];
+static gpioISR_t gpioISR [PI_MAX_USER_GPIO+1];
+
static gpioGetSamples_t gpioGetSamples;
static gpioInfo_t gpioInfo [PI_MAX_GPIO+1];
PI_DEFAULT_DMA_SECONDARY_CHANNEL,
PI_DEFAULT_SOCKET_PORT,
PI_DEFAULT_IF_FLAGS,
- DBG_MIN_LEVEL,
- 0,
PI_DEFAULT_MEM_ALLOC_MODE,
+ 0, /* dbgLevel */
+ 0, /* alertFreq */
+ 0, /* internals */
};
/* no initialisation required */
}
+/* ----------------------------------------------------------------------- */
+
+static int myGpioRead(unsigned gpio)
+{
+ if ((*(gpioReg + GPLEV0 + BANK) & BIT) != 0) return PI_ON;
+ else return PI_OFF;
+}
+
/* ----------------------------------------------------------------------- */
static int myPermit(unsigned gpio)
{
- if ((gpio <= PI_MAX_GPIO) &&
- (gpioMask & ((uint64_t)(1)<<gpio)))
- return 1;
- else
- return 0;
+ if (gpio <= PI_MAX_GPIO)
+ {
+ if (gpioMask & ((uint64_t)(1)<<gpio)) return 1;
+ else return 0;
+ }
+ return 1; /* will fail for bad gpio number */
}
static void flushMemory(void)
res = gpioCustom1(p[1], p[2], buf, p[3]);
break;
-
case PI_CMD_CF2:
/* a couple of extra precautions for untrusted code */
if (p[2] > bufSize) p[2] = bufSize;
if (res > p[2]) res = p[2];
break;
+ case PI_CMD_CGI: res = gpioCfgGetInternals(); break;
+
+ case PI_CMD_CSI: res = gpioCfgSetInternals(p[1]); break;
+
case PI_CMD_GDC: res = gpioGetPWMdutycycle(p[1]); break;
case PI_CMD_GPW: res = gpioGetServoPulsewidth(p[1]); break;
static void myGpioSetServo(unsigned gpio, int oldVal, int newVal)
{
- int switchGpioOff;
int newOff, oldOff, realRange, cycles, i;
DBG(DBG_INTERNAL,
"myGpioSetServo %d from %d to %d", gpio, oldVal, newVal);
- switchGpioOff = 0;
-
realRange = pwmRealRange[clkCfg[gpioCfg.clockMicros].servoIdx];
cycles = pwmCycles [clkCfg[gpioCfg.clockMicros].servoIdx];
for (i=0; i<SUPERCYCLE; i+=cycles)
myClearGpioOn(gpio, i);
- for (i=0; i<SUPERLEVEL; i+=realRange)
- myClearGpioOff(gpio, i+oldOff);
+ /* if in pulse then delay for the last cycle to complete */
- switchGpioOff = 1;
- }
+ if (myGpioRead(gpio)) myGpioDelay(PI_MAX_SERVO_PULSEWIDTH);
- if (switchGpioOff)
- {
- *(gpioReg + GPCLR0) = (1<<gpio);
- *(gpioReg + GPCLR0) = (1<<gpio);
+ /* deschedule gpio off */
+
+ for (i=0; i<SUPERLEVEL; i+=realRange)
+ myClearGpioOff(gpio, i+oldOff);
}
}
}
break;
case SIGPIPE:
- case SIGCHLD:
case SIGWINCH:
DBG(DBG_USER, "signal %d ignored", signum);
break;
+ case SIGCHLD:
+ /* Used to notify threads of events */
+ break;
+
default:
DBG(DBG_ALWAYS, "Unhandled signal %d, terminating\n", signum);
gpioTerminate();
}
}
+unsigned alert_delays[]={
+ 1000, 1068, 1145, 1235,
+ 1339, 1463, 1613, 1796,
+ 2027, 2326, 2727, 3297,
+ 4167, 5660, 8823, 20000};
+
/* ======================================================================= */
static void * pthAlertThread(void *x)
struct timespec req, rem;
uint32_t oldLevel, newLevel, level, reportedLevel;
uint32_t oldSlot, newSlot;
- uint32_t tick, expected;
+ uint32_t tick, expected, nowTick;
int32_t diff;
int cycle, pulse;
int emit, seqno, emitted;
int b, n, v;
int err;
int stopped;
+ int delayTicks;
+ uint32_t nextWakeTick;
+ int moreToDo;
+ int max_emits;
char fifo[32];
req.tv_sec = 0;
reportedLevel = gpioReg[GPLEV0];
- tick = systReg[SYST_CLO];
-
- gpioStats.startTick = tick;
-
oldSlot = dmaCurrentSlot(dmaNowAtICB());
cycle = (oldSlot/PULSE_PER_CYCLE);
stopped = 0;
- while (1)
- {
-
- if (dmaIn[DMA_CONBLK_AD])
- {
- if (stopped)
- {
- DBG(DBG_STARTUP, "****** GOING ******");
- stopped = 0;
- }
- }
- else
- {
- stopped = 1;
-
- myGpioDelay(5000);
-
- if (runState == PI_RUNNING)
- {
- /* should never be executed, leave code just in case */
-
- gpioCfg.showStats = 1;
-
- dmaInitCbs();
- flushMemory();
- initDMAgo((uint32_t *)dmaIn, (uint32_t)dmaIBus[0]);
- myGpioDelay(5000); /* let DMA run for a while */
- oldSlot = dmaCurrentSlot(dmaNowAtICB());
- gpioStats.DMARestarts++;
- }
- }
-
- gpioStats.alertTicks++;
+ moreToDo = 0;
- req.tv_nsec = 850000;
+ tick = systReg[SYST_CLO];
- while (nanosleep(&req, &rem))
- {
- req.tv_sec = rem.tv_sec;
- req.tv_nsec = rem.tv_nsec;
- }
+ nextWakeTick =
+ tick + alert_delays[(gpioCfg.internals>>PI_CFG_ALERT_FREQ)&15];
+ while (1)
+ {
newSlot = dmaCurrentSlot(dmaNowAtICB());
numSamples = 0;
if (diff < 0)
{
- /* shouldn't happen */
-
- //gpioCfg.showStats = 1;
-
gpioStats.diffTick[0]++;
}
else if (diff >= TICKSLOTS)
{
- /* shouldn't happen */
-
- //gpioCfg.showStats = 1;
-
gpioStats.diffTick[TICKSLOTS-1]++;
}
}
}
+ if (oldSlot == newSlot) moreToDo = 0; else moreToDo = 1;
+
/* should gpioGetSamples be called */
if (changedBits)
if (emit)
{
gpioNotify[n].lastReportTick = tick;
+ max_emits = gpioNotify[n].max_emits;
if (emit > gpioStats.maxEmit) gpioStats.maxEmit = emit;
while (emit > 0)
{
- if (emit > MAX_EMITS)
+ if (emit > max_emits)
{
gpioStats.emitFrags++;
err = write(gpioNotify[n].fd,
gpioReport+emitted,
- MAX_EMITS*sizeof(gpioReport_t));
+ max_emits*sizeof(gpioReport_t));
- if (err != (MAX_EMITS*sizeof(gpioReport_t)))
+ if (err != (max_emits*sizeof(gpioReport_t)))
{
if (err < 0)
{
intNotifyBits();
break;
}
+ else gpioStats.wouldBlockPipeWrite++;
+ }
+ else
+ {
+ gpioCfg.internals |= PI_CFG_STATS;
+ gpioStats.shortPipeWrite++;
+ DBG(DBG_ALWAYS, "emitted %d, asked for %d",
+ err/sizeof(gpioReport_t), max_emits);
}
}
+ else gpioStats.goodPipeWrite++;
- emitted += MAX_EMITS;
- emit -= MAX_EMITS;
+ emitted += max_emits;
+ emit -= max_emits;
}
else
{
intNotifyBits();
break;
}
+ else gpioStats.wouldBlockPipeWrite++;
+ }
+ else
+ {
+ gpioCfg.internals |= PI_CFG_STATS;
+ gpioStats.shortPipeWrite++;
+ DBG(DBG_ALWAYS, "emitted %d, asked for %d",
+ err/sizeof(gpioReport_t), emit);
}
}
+ else gpioStats.goodPipeWrite++;
emitted += emit;
emit = 0;
gpioStats.maxSamples = numSamples;
gpioStats.numSamples += numSamples;
+
+ /* Check that DMA is running okay */
+
+ if (dmaIn[DMA_CONBLK_AD])
+ {
+ if (stopped)
+ {
+ DBG(DBG_STARTUP, "****** GOING ******");
+ stopped = 0;
+ }
+ }
+ else
+ {
+ stopped = 1;
+
+ myGpioDelay(5000);
+
+ if (runState == PI_RUNNING)
+ {
+ /* should never be executed, leave code just in case */
+
+ gpioCfg.internals |= PI_CFG_STATS;
+
+ dmaInitCbs();
+ flushMemory();
+ initDMAgo((uint32_t *)dmaIn, (uint32_t)dmaIBus[0]);
+ myGpioDelay(5000); /* let DMA run for a while */
+ oldSlot = dmaCurrentSlot(dmaNowAtICB());
+ gpioStats.DMARestarts++;
+ }
+ }
+
+ nowTick = systReg[SYST_CLO];
+
+ if (moreToDo)
+ {
+ gpioStats.moreToDo++;
+
+ /* rebase wake up time */
+
+ nextWakeTick = nowTick +
+ alert_delays[(gpioCfg.internals>>PI_CFG_ALERT_FREQ)&15];
+
+ req.tv_nsec = 0;
+ }
+ else
+ {
+ delayTicks = nextWakeTick - nowTick;
+
+ if (delayTicks < 0)
+ {
+ gpioStats.lateTicks++;
+
+ /* rebase wake up time */
+
+ nextWakeTick = nowTick +
+ alert_delays[(gpioCfg.internals>>PI_CFG_ALERT_FREQ)&15];
+
+ req.tv_nsec = 0;
+ }
+ else
+ {
+ gpioStats.alertTicks++;
+
+ nextWakeTick +=
+ alert_delays[(gpioCfg.internals>>PI_CFG_ALERT_FREQ)&15];
+
+ req.tv_nsec = (delayTicks * 1000);
+ }
+ }
+
+ if (req.tv_nsec)
+ {
+ req.tv_sec = 0;
+
+ while (nanosleep(&req, &rem))
+ {
+ req.tv_sec = rem.tv_sec;
+ req.tv_nsec = rem.tv_nsec;
+ }
+ }
+
+ nextWakeTick +=
+ alert_delays[(gpioCfg.internals>>PI_CFG_ALERT_FREQ)&15];
+
}
return 0;
switch (p[0])
{
case PI_CMD_NOIB:
+
p[3] = gpioNotifyOpenInBand(sock);
- /* Enable the Nagle algorithm. */
+ /* Enable the Nagle algorithm. */
opt = 0;
setsockopt(
sock, IPPROTO_TCP, TCP_NODELAY, (char*)&opt, sizeof(int));
+
break;
case PI_CMD_PROCP:
param.sched_priority = sched_get_priority_max(SCHED_FIFO);
- sched_setscheduler(0, SCHED_FIFO, ¶m);
+ if (gpioCfg.internals & PI_CFG_RT_PRIORITY)
+ sched_setscheduler(0, SCHED_FIFO, ¶m);
initClock(1); /* initialise main clock */
if (dmaReg != MAP_FAILED) dmaOut[DMA_CS] = DMA_CHANNEL_RESET;
#ifndef EMBEDDED_IN_VM
- if (gpioCfg.showStats)
+ if (gpioCfg.internals & PI_CFG_STATS)
{
+ fprintf(stderr,
+ "\n#####################################################\n");
fprintf(stderr,
"If you didn't request stats please cut & paste the\n"
"following and e-mail to pigpio@abyz.co.uk\n");
+ fprintf(stderr, "pigpio version=%d internals=%X\n",
+ PIGPIO_VERSION, gpioCfg.internals);
+
fprintf(stderr,
"micros=%d allocMode=%d dmaInitCbs=%d DMARestarts=%d\n",
gpioCfg.clockMicros, gpioCfg.memAllocMode,
gpioStats.numSamples, gpioStats.maxSamples,
gpioStats.maxEmit, gpioStats.emitFrags);
- fprintf(stderr, "cbTicks %d, cbCalls %u alertTicks %u\n",
- gpioStats.cbTicks, gpioStats.cbCalls, gpioStats.alertTicks);
+ fprintf(stderr, "cbTicks %d, cbCalls %u\n",
+ gpioStats.cbTicks, gpioStats.cbCalls);
- for (i=0; i< TICKSLOTS; i++)
- fprintf(stderr, "%9u ", gpioStats.diffTick[i]);
+ fprintf(stderr, "pipe: good %u, short %u, would block %u\n",
+ gpioStats.goodPipeWrite, gpioStats.shortPipeWrite,
+ gpioStats.wouldBlockPipeWrite);
- fprintf(stderr, "\n");
+ fprintf(stderr, "alertTicks %u, lateTicks %u, moreToDo %u\n",
+ gpioStats.alertTicks, gpioStats.lateTicks, gpioStats.moreToDo);
- fprintf(stderr, "\n");
+ for (i=0; i< TICKSLOTS; i++)
+ fprintf(stderr, "%9u ", gpioStats.diffTick[i]);
fprintf(stderr,
- "#####################################################\n");
+ "\n#####################################################\n\n\n");
}
#endif
"chain counters nested too deep (at %d)", i);
stk_pos[stk_lev++] = cb;
+
i += 2;
}
else if (cmd == 1) /* loop end */
counters++;
}
- loop = -1;
}
else if (cmd == 2) /* delay us */
{
p->next = waveCbPOadr(chainGetCB(cb));
}
}
+ else if (cmd == 3) /* repeat loop forever */
+ {
+ i += 2;
+
+ loop = 0;
+ if (--stk_lev >= 0) loop = stk_pos[stk_lev];
+
+ if ((loop < 1) || (loop == cb))
+ SOFT_ERROR(PI_BAD_CHAIN_LOOP,
+ "empty chain loop (at %d)", i);
+
+ chaincb = chainGetCB(cb++);
+ if (chaincb < 0)
+ SOFT_ERROR(PI_CHAIN_TOO_BIG, "chain is too long (%d)", cb);
+
+ if (i < bufSize)
+ SOFT_ERROR(PI_BAD_FOREVER,
+ "loop forever must be last command");
+
+ p = rawWaveCBAdr(chaincb);
+
+ /* dummy src and dest */
+ p->info = NORMAL_DMA;
+ p->src = (uint32_t) (&dmaOBus[0]->periphData);
+ p->dst = (uint32_t) (&dmaOBus[0]->periphData);
+ p->length = 4;
+ p->next = waveCbPOadr(chainGetCB(loop));
+ }
else
SOFT_ERROR(PI_BAD_CHAIN_CMD,
"unknown chain command (255 %d)", cmd);
return 0;
}
+static void *pthISRThread(void *x)
+{
+ gpioISR_t *isr = x;
+ int fd;
+ int retval;
+ uint32_t tick;
+ int level;
+ uint32_t levels;
+ struct pollfd pfd;
+ char buf[64];
+
+ DBG(DBG_USER, "gpio=%d edge=%d timeout=%d f=%x u=%d data=%x",
+ isr->gpio, isr->edge, isr->timeout, (uint32_t)isr->func,
+ isr->ex, (uint32_t)isr->userdata);
+
+ sprintf(buf, "/sys/class/gpio/gpio%d/value", isr->gpio);
+
+ if ((fd = open(buf, O_RDONLY)) < 0)
+ {
+ DBG(DBG_ALWAYS, "gpio %d not exported", isr->gpio);
+ return NULL;
+ }
+
+ pfd.fd = fd;
+
+ pfd.events = POLLPRI;
+
+ lseek(fd, 0, SEEK_SET); /* consume any prior interrupt */
+ read(fd, buf, sizeof buf);
+
+ while (1)
+ {
+ retval = poll(&pfd, 1, isr->timeout); /* wait for interrupt */
+
+ tick = systReg[SYST_CLO];
+
+ levels = *(gpioReg + GPLEV0);
+
+ if (retval >= 0)
+ {
+ lseek(fd, 0, SEEK_SET); /* consume interrupt */
+ read(fd, buf, sizeof buf);
+ if (retval)
+ {
+ if (levels & (1<<isr->gpio)) level = PI_ON; else level = PI_OFF;
+ }
+ else level = PI_TIMEOUT;
+
+ if (isr->ex) (isr->func)(isr->gpio, level, tick, isr->userdata);
+ else (isr->func)(isr->gpio, level, tick);
+ }
+ }
+
+ return NULL;
+}
+
+
+/* ----------------------------------------------------------------------- */
+
+static int intGpioSetISRFunc(
+ unsigned gpio,
+ unsigned edge,
+ int timeout,
+ void *f,
+ int user,
+ void *userdata)
+{
+ char buf[64];
+
+ char *edge_str[]={"rising\n", "falling\n", "both\n"};
+ int fd;
+ int err;
+
+ DBG(DBG_INTERNAL,
+ "gpio=%d edge=%d timeout=%d function=%08X user=%d userdata=%08X",
+ gpio, edge, timeout, (uint32_t)f, user, (uint32_t)userdata);
+
+ if (f)
+ {
+ if (!gpioISR[gpio].inited) /* export gpio if unexported */
+ {
+ fd = open("/sys/class/gpio/export", O_WRONLY);
+ if (fd < 0) return PI_BAD_ISR_INIT;
+
+ /* ignore write fail if already exported */
+ sprintf(buf, "%d\n", gpio);
+ err = write(fd, buf, strlen(buf));
+ close(fd);
+
+ sprintf(buf, "/sys/class/gpio/gpio%d/direction", gpio);
+ fd = open(buf, O_WRONLY);
+ if (fd < 0) return PI_BAD_ISR_INIT;
+
+ err = write(fd, "in\n", 3);
+ close(fd);
+ if (err != 3) return PI_BAD_ISR_INIT;
+
+ gpioISR[gpio].gpio = gpio;
+ gpioISR[gpio].edge = -1;
+ gpioISR[gpio].timeout = -1;
+
+ gpioISR[gpio].inited = 1;
+ }
+
+ if (gpioISR[gpio].edge != edge)
+ {
+ sprintf(buf, "/sys/class/gpio/gpio%d/edge", gpio);
+ fd = open(buf, O_WRONLY);
+ if (fd < 0) return PI_BAD_ISR_INIT;
+
+ err = write(fd, edge_str[edge], strlen(edge_str[edge]));
+ close(fd);
+ if (err != strlen(edge_str[edge])) return PI_BAD_ISR_INIT;
+
+ gpioISR[gpio].edge = edge;
+
+ if (gpioISR[gpio].pth != NULL)
+ pthread_kill(*gpioISR[gpio].pth, SIGCHLD);
+ }
+
+ if (timeout <= 0) timeout = -1;
+ if (gpioISR[gpio].timeout != timeout)
+ {
+ gpioISR[gpio].timeout = timeout;
+
+ if (gpioISR[gpio].pth != NULL)
+ pthread_kill(*gpioISR[gpio].pth, SIGCHLD);
+ }
+
+ gpioISR[gpio].func = f;
+ gpioISR[gpio].ex = user;
+ gpioISR[gpio].userdata = userdata;
+
+ if (gpioISR[gpio].pth == NULL)
+ gpioISR[gpio].pth = gpioStartThread(pthISRThread, &gpioISR[gpio]);
+ }
+ else /* null function, delete ISR, unexport gpio */
+ {
+ if (gpioISR[gpio].pth) /* delete any existing ISR */
+ {
+ gpioStopThread(gpioISR[gpio].pth);
+ gpioISR[gpio].func = NULL;
+ gpioISR[gpio].pth = NULL;
+ }
+
+ if (gpioISR[gpio].inited) /* unexport any gpio */
+ {
+ fd = open("/sys/class/gpio/unexport", O_WRONLY);
+ if (fd < 0) return PI_BAD_ISR_INIT;
+ sprintf(buf, "%d\n", gpio);
+ err = write(fd, buf, strlen(buf));
+ close(fd);
+ if (err != sizeof(buf)) return PI_BAD_ISR_INIT;
+ gpioISR[gpio].inited = 0;
+ }
+ }
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+int gpioSetISRFunc(
+ unsigned gpio,
+ unsigned edge,
+ int timeout,
+ gpioISRFunc_t f)
+{
+ DBG(DBG_USER, "gpio=%d edge=%d timeout=%d function=%08X",
+ gpio, edge, timeout, (uint32_t)f);
+
+ CHECK_INITED;
+
+ if (gpio > PI_MAX_USER_GPIO)
+ SOFT_ERROR(PI_BAD_USER_GPIO, "bad gpio (%d)", gpio);
+
+ if (edge > EITHER_EDGE)
+ SOFT_ERROR(PI_BAD_EDGE, "bad ISR edge (%d)", edge);
+
+ return intGpioSetISRFunc(gpio, edge, timeout, f, 0, NULL);
+}
+
+
+/* ----------------------------------------------------------------------- */
+
+int gpioSetISRFuncEx(
+ unsigned gpio,
+ unsigned edge,
+ int timeout,
+ gpioAlertFuncEx_t f,
+ void *userdata)
+{
+ DBG(DBG_USER, "gpio=%d edge=%d timeout=%d function=%08X userdata=%08X",
+ gpio, edge, timeout, (uint32_t)f, (uint32_t)userdata);
+
+ CHECK_INITED;
+
+ if (gpio > PI_MAX_USER_GPIO)
+ SOFT_ERROR(PI_BAD_USER_GPIO, "bad gpio (%d)", gpio);
+
+ if (edge > EITHER_EDGE)
+ SOFT_ERROR(PI_BAD_EDGE, "bad ISR edge (%d)", edge);
+
+ return intGpioSetISRFunc(gpio, edge, timeout, f, 1, userdata);
+}
+
/* ----------------------------------------------------------------------- */
gpioNotify[slot].bits = 0;
gpioNotify[slot].fd = fd;
gpioNotify[slot].pipe = 1;
+ gpioNotify[slot].max_emits = MAX_EMITS;
gpioNotify[slot].lastReportTick = gpioTick();
return slot;
gpioNotify[slot].bits = 0;
gpioNotify[slot].fd = fd;
gpioNotify[slot].pipe = 0;
+ gpioNotify[slot].max_emits = MAX_EMITS;
gpioNotify[slot].lastReportTick = gpioTick();
return slot;
{
pthread_cancel(*pth);
pthread_join(*pth, NULL);
+ free(pth);
}
}
/* ----------------------------------------------------------------------- */
-int gpioCfgInternals(unsigned cfgWhat, int cfgVal)
+uint32_t gpioCfgGetInternals(void)
+{
+ return gpioCfg.internals;
+}
+
+int gpioCfgSetInternals(uint32_t cfgVal)
+{
+ gpioCfg.internals = cfgVal;
+ gpioCfg.dbgLevel = cfgVal & 0xF;
+ gpioCfg.alertFreq = (cfgVal>>4) & 0xF;
+ return 0;
+}
+
+int gpioCfgInternals(unsigned cfgWhat, unsigned cfgVal)
{
int retVal = PI_BAD_CFG_INTERNAL;
DBG(DBG_USER, "cfgWhat=%u, cfgVal=%d", cfgWhat, cfgVal);
- /*
- 133084774
- 207081315
- 293640712
- 394342930
- 472769257
- 430873902
- 635370313
- 684442696
- 786301093
- 816051706
- 858202631
- 997413601
- */
-
switch(cfgWhat)
{
case 562484977:
- gpioCfg.showStats = cfgVal;
+ if (cfgVal) gpioCfg.internals |= PI_CFG_STATS;
+ else gpioCfg.internals &= (~PI_CFG_STATS);
- DBG(DBG_ALWAYS, "showStats is %u", cfgVal);
+ DBG(DBG_ALWAYS, "show stats is %u", cfgVal);
retVal = 0;
case 984762879:
- if (cfgVal < DBG_ALWAYS) cfgVal = DBG_ALWAYS;
-
- if (cfgVal > DBG_MAX_LEVEL) cfgVal = DBG_MAX_LEVEL;
-
- gpioCfg.dbgLevel = cfgVal;
+ if ((cfgVal >= DBG_ALWAYS) && (cfgVal <= DBG_MAX_LEVEL))
+ {
+
+ gpioCfg.dbgLevel = cfgVal;
+ gpioCfg.internals = (gpioCfg.internals & (~0xF)) | cfgVal;
- DBG(DBG_ALWAYS, "Debug level is %u", cfgVal);
+ DBG(DBG_ALWAYS, "Debug level is %u", cfgVal);
- retVal = 0;
+ retVal = 0;
+ }
break;
}
return retVal;
}
+
/* include any user customisations */
#include "custom.cext"
#include <stdint.h>
#include <pthread.h>
-#define PIGPIO_VERSION 37
+#define PIGPIO_VERSION 38
/*TEXT
gpioSetAlertFuncEx Request a gpio change callback, extended
+gpioSetISRFunc Request a gpio interrupt callback
+gpioSetISRFuncEx Request a gpio interrupt callback, extended
+
gpioSetSignalFunc Request a signal callback
gpioSetSignalFuncEx Request a signal callback, extended
gpioCfgDMAchannels Configure the DMA channels
gpioCfgPermissions Configure the gpio access permissions
gpioCfgInterfaces Configure user interfaces
-gpioCfgInternals Configure miscellaneous internals
gpioCfgSocketPort Configure socket port
gpioCfgMemAlloc Configure DMA memory allocation mode
+gpioCfgInternals Configure miscellaneous internals (DEPRECATED)
+
+gpioCfgGetInternals Get internal configuration settings
+gpioCfgSetInternals Set internal configuration settings
+
CUSTOM
gpioCustom1 User custom function 1
uint32_t tick,
void *userdata);
+typedef void (*gpioISRFunc_t) (int gpio,
+ int level,
+ uint32_t tick);
+
+typedef void (*gpioISRFuncEx_t) (int gpio,
+ int level,
+ uint32_t tick,
+ void *userdata);
+
typedef void (*gpioTimerFunc_t) (void);
typedef void (*gpioTimerFuncEx_t) (void *userdata);
#define PI_MEM_ALLOC_PAGEMAP 1
#define PI_MEM_ALLOC_MAILBOX 2
+/* gpioCfgInternals */
+
+#define PI_CFG_DBG_LEVEL 0 /* bits 0-3 */
+#define PI_CFG_ALERT_FREQ 4 /* bits 4-7 */
+#define PI_CFG_RT_PRIORITY (1<<8)
+#define PI_CFG_STATS (1<<9)
+
+#define PI_CFG_ILLEGAL_VAL (1<<10)
+
+/* gpioISR */
+
+#define RISING_EDGE 0
+#define FALLING_EDGE 1
+#define EITHER_EDGE 2
+
+
/*F*/
int gpioInitialise(void);
/*D
// call aFunction whenever gpio 4 changes state
-gpioSetAlertFunc(4, aFunction);
+gpioSetAlertFunc(4F, aFunction);
...
D*/
D*/
+/*F*/
+int gpioSetISRFunc(
+ unsigned user_gpio, unsigned edge, int timeout, gpioISRFunc_t f);
+/*D
+Registers a function to be called (a callback) whenever the specified
+gpio interrupt occurs.
+
+. .
+user_gpio: 0-31
+ edge: RISING_EDGE, FALLING_EDGE, or EITHER_EDGE
+ timeout: interrupt timeout in milliseconds (<=0 to cancel)
+ f: the callback function
+. .
+
+Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_EDGE,
+or PI_BAD_ISR_INIT.
+
+One function may be registered per gpio.
+
+The function is passed the gpio, the current level, and the
+current tick. The level will be PI_TIMEOUT if the optional
+interrupt timeout expires.
+
+The underlying Linux sysfs gpio interface is used to provide
+the interrupt services.
+
+The first time the function is called, with a non-NULL f, the
+gpio is exported, set to be an input, and set to interrupt
+on the given edge and timeout.
+
+Subsequent calls, with a non-NULL f, can vary one or more of the
+edge, timeout, or function.
+
+The ISR may be cancelled by passing a NULL f, in which case the
+gpio is unexported.
+
+The tick is that read at the time the process was informed of
+the interrupt. This will be a variable number of microseconds
+after the interrupt occurred. Typically the latency will be of
+the order of 50 microseconds. The latency is not guaranteed
+and will vary with system load.
+
+The level is that read at the time the process was informed of
+the interrupt, or PI_TIMEOUT if the optional interrupt timeout
+expired. It may not be the same as the expected edge as
+interrupts happening in rapid succession may be missed by the
+kernel (i.e. this mechanism can not be used to capture several
+interrupts only a few microseconds apart).
+D*/
+
+
+/*F*/
+int gpioSetISRFuncEx(
+ unsigned user_gpio,
+ unsigned edge,
+ int timeout,
+ gpioISRFuncEx_t f,
+ void *userdata);
+/*D
+Registers a function to be called (a callback) whenever the specified
+gpio interrupt occurs.
+
+. .
+user_gpio: 0-31
+ edge: RISING_EDGE, FALLING_EDGE, or EITHER_EDGE
+ timeout: interrupt timeout in milliseconds (<=0 to cancel)
+ f: the callback function
+ userdata: pointer to arbitrary user data
+. .
+
+Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_EDGE,
+or PI_BAD_ISR_INIT.
+
+The function is passed the gpio, the current level, the
+current tick, and the userdata pointer.
+
+Only one of [*gpioSetISRFunc*] or [*gpioSetISRFuncEx*] can be
+registered per gpio.
+
+See [*gpioSetISRFunc*] for further details.
+D*/
+
+
/*F*/
int gpioNotifyOpen(void);
/*D
The following command codes are supported:
-Name @ Cmd & Data @ Meaning
-Loop Start @ 255 0 @ Identify start of a wave block
-Loop Repeat @ 255 1 x y @ loop x + y*256 times
-Delay @ 255 2 x y @ delay x + y*256 microseconds
+Name @ Cmd & Data @ Meaning
+Loop Start @ 255 0 @ Identify start of a wave block
+Loop Repeat @ 255 1 x y @ loop x + y*256 times
+Delay @ 255 2 x y @ delay x + y*256 microseconds
+Loop Forever @ 255 3 @ loop forever
+
+If present Loop Forever must be the last entry in the chain.
The code is currently dimensioned to support a chain with roughly
600 entries and 20 loop counters.
D*/
/*F*/
-int gpioCfgInternals(unsigned cfgWhat, int cfgVal);
+int gpioCfgInternals(unsigned cfgWhat, unsigned cfgVal);
/*D
Used to tune internal settings.
. .
D*/
+/*F*/
+uint32_t gpioCfgGetInternals(void);
+/*D
+This function returns the current library internal configuration
+settings.
+D*/
+
+/*F*/
+int gpioCfgSetInternals(uint32_t cfgVal);
+/*D
+This function sets the current library internal configuration
+settings.
+
+. .
+cfgVal: see source code
+. .
+D*/
+
+
/*F*/
int gpioCustom1(unsigned arg1, unsigned arg2, char *argx, unsigned argc);
/*D
The hardware clock frequency.
. .
-#define PI_HW_CLK_MIN_FREQ 4689
-#define PI_HW_CLK_MAX_FREQ 250000000
+PI_HW_CLK_MIN_FREQ 4689
+PI_HW_CLK_MAX_FREQ 250000000
. .
count::
waveform.
. .
-#define PI_MIN_WAVE_DATABITS 1
-#define PI_MAX_WAVE_DATABITS 32
+PI_MIN_WAVE_DATABITS 1
+PI_MAX_WAVE_DATABITS 32
. .
DMAchannel::0-14
The number may vary between 0 and range (default 255) where
0 is off and range is fully on.
+edge::0-2
+The type of gpio edge to generate an intrrupt. See[*gpioSetISRFunc*],
+and [*gpioSetISRFuncEx*].
+
+. .
+RISING_EDGE 0
+FALLING_EDGE 1
+EITHER_EDGE 2
+. .
+
f::
A function.
(const gpioSample_t *samples, int numSamples, void *userdata);
. .
+gpioISRFunc_t::
+. .
+typedef void (*gpioISRFunc_t)
+ (int gpio, int level, uint32_t tick);
+. .
+
+gpioISRFuncEx_t::
+. .
+typedef void (*gpioISRFuncEx_t)
+ (int gpio, int level, uint32_t tick, void *userdata);
+. .
+
gpioPulse_t::
. .
typedef struct
The hardware PWM dutycycle.
. .
-#define PI_HW_PWM_RANGE 1000000
+PI_HW_PWM_RANGE 1000000
. .
PWMfreq::5-250K
The hardware PWM frequency.
. .
-#define PI_HW_PWM_MIN_FREQ 1
-#define PI_HW_PWM_MAX_FREQ 125000000
+PI_HW_PWM_MIN_FREQ 1
+PI_HW_PWM_MAX_FREQ 125000000
. .
range::25-40000
to a waveform.
. .
-#define PI_MIN_WAVE_HALFSTOPBITS 2
-#define PI_MAX_WAVE_HALFSTOPBITS 8
+PI_MIN_WAVE_HALFSTOPBITS 2
+PI_MAX_WAVE_HALFSTOPBITS 8
. .
*str::
An array of characters.
timeout::
-A gpio watchdog timeout in milliseconds.
+A gpio level change timeout in milliseconds.
+
+[*gpioSetWatchdog*]
. .
PI_MIN_WDOG_TIMEOUT 0
PI_MAX_WDOG_TIMEOUT 60000
. .
+[*gpioSetISRFunc*] and [*gpioSetISRFuncEx*]
+. .
+<=0 cancel timeout
+>0 timeout after specified milliseconds
+. .
+
timer::
. .
PI_MIN_TIMER 0
#define PI_CMD_SLRI 94
+#define PI_CMD_CGI 95
+#define PI_CMD_CSI 96
+
#define PI_CMD_NOIB 99
/*DEF_E*/
#define PI_CHAIN_TOO_BIG -119 // chain is too long
#define PI_DEPRECATED -120 // deprecated function removed
#define PI_BAD_SER_INVERT -121 // bit bang serial invert not 0 or 1
+#define PI_BAD_EDGE -122 // bad ISR edge value, not 0-2
+#define PI_BAD_ISR_INIT -123 // bad ISR initialisation
+#define PI_BAD_FOREVER -124 // loop forever must be last chain command
#define PI_PIGIF_ERR_0 -2000
#define PI_PIGIF_ERR_99 -2099
#define PI_DEFAULT_UPDATE_MASK_COMPUTE 0x00FFFFFFFFFFFFLL
#define PI_DEFAULT_MEM_ALLOC_MODE PI_MEM_ALLOC_AUTO
+#define PI_DEFAULT_CFG_INTERNALS 0
+
/*DEF_E*/
#endif
import os
import atexit
-VERSION = "1.21"
+VERSION = "1.22"
exceptions = True
_PI_CMD_WVCHA=93
-_PI_CMD_SLRI= 94
+_PI_CMD_SLRI =94
# pigpio error numbers
def run(self):
"""Runs the notification thread."""
- lastLevel = 0
+ lastLevel = _pigpio_command(self.control, _PI_CMD_BR1, 0, 0)
MSG_SIZ = 12
The following command codes are supported:
- Name @ Cmd & Data @ Meaning
- Loop Start @ 255 0 @ Identify start of a wave block
- Loop Repeat @ 255 1 x y @ loop x + y*256 times
- Delay @ 255 2 x y @ delay x + y*256 microseconds
+ Name @ Cmd & Data @ Meaning
+ Loop Start @ 255 0 @ Identify start of a wave block
+ Loop Repeat @ 255 1 x y @ loop x + y*256 times
+ Delay @ 255 2 x y @ delay x + y*256 microseconds
+ Loop Forever @ 255 3 @ loop forever
+
+ If present Loop Forever must be the last entry in the chain.
The code is currently dimensioned to support a chain with
roughly 600 entries and 20 loop counters.
100-10000
default 120
+.IP "\fB-c value\fP"
+library internal settings
+
+default 0
+
.IP "\fB-d value\fP"
primary DMA channel
0-14
.br
.br
-There are two special cases.
+There are several special cases.
+
+.br
+
+.br
+The activity LED (green) may be written (gpio 16 for type 1 and 2
+boards, gpio 47 for type 3 boards)
.br
.br
-The activity LED may be written (gpio 16 for type 1 and 2
-boards, gpio 47 for type 3 boards).
+The power LED (red) may be written on type 3 boards (gpio 35).
.br
*/
/*
-This version is for pigpio version 30+
+This version is for pigpio version 38+
*/
#include <sys/types.h>
static unsigned memAllocMode = PI_DEFAULT_MEM_ALLOC_MODE;
static uint64_t updateMask = -1;
+static uint32_t cfgInternals = PI_DEFAULT_CFG_INTERNALS;
+
static int updateMaskSet = 0;
static FILE * errFifo;
"Usage: sudo pigpiod [OPTION] ...\n" \
" -a value, DMA mode, 0=AUTO, 1=PMAP, 2=MBOX, default AUTO\n" \
" -b value, gpio sample buffer in milliseconds, default 120\n" \
+ " -c value, library internal settings, default 0\n" \
" -d value, primary DMA channel, 0-14, default 14\n" \
" -e value, secondary DMA channel, 0-6, default 5\n" \
" -f, disable fifo interface, default enabled\n" \
"\n");
}
+static uint64_t getNum(char *str, int *err)
+{
+ uint64_t val;
+ char *endptr;
+
+ *err = 0;
+ val = strtoll(str, &endptr, 0);
+ if (*endptr) {*err = 1; val = -1;}
+ return val;
+}
+
static void initOpts(int argc, char *argv[])
{
- int i, opt;
- uint64_t mask;
- char * endptr;
+ int opt, err, i;
+ int64_t mask;
- while ((opt = getopt(argc, argv, "a:b:d:e:fkp:s:t:x:")) != -1)
+ while ((opt = getopt(argc, argv, "a:b:c:d:e:fkp:s:t:x:")) != -1)
{
- i = -1;
-
switch (opt)
{
case 'a':
- i = atoi(optarg);
+ i = getNum(optarg, &err);
if ((i >= PI_MEM_ALLOC_AUTO) && (i <= PI_MEM_ALLOC_MAILBOX))
memAllocMode = i;
else fatal("invalid -a option (%d)", i);
break;
case 'b':
- i = atoi(optarg);
+ i = getNum(optarg, &err);
if ((i >= PI_BUF_MILLIS_MIN) && (i <= PI_BUF_MILLIS_MAX))
bufferSizeMilliseconds = i;
else fatal("invalid -b option (%d)", i);
break;
+ case 'c':
+ i = getNum(optarg, &err);
+ if ((i >= 0) && (i < PI_CFG_ILLEGAL_VAL))
+ cfgInternals = i;
+ else fatal("invalid -c option (%x)", i);
+ break;
+
case 'd':
- i = atoi(optarg);
+ i = getNum(optarg, &err);
if ((i >= PI_MIN_DMA_CHANNEL) && (i <= PI_MAX_PRIMARY_CHANNEL))
DMAprimaryChannel = i;
else fatal("invalid -d option (%d)", i);
break;
case 'e':
- i = atoi(optarg);
+ i = getNum(optarg, &err);
if ((i >= PI_MIN_DMA_CHANNEL) && (i <= PI_MAX_SECONDARY_CHANNEL))
DMAsecondaryChannel = i;
else fatal("invalid -e option (%d)", i);
break;
case 'p':
- i = atoi(optarg);
+ i = getNum(optarg, &err);
if ((i >= PI_MIN_SOCKET_PORT) && (i <= PI_MAX_SOCKET_PORT))
socketPort = i;
else fatal("invalid -p option (%d)", i);
break;
case 's':
- i = atoi(optarg);
+ i = getNum(optarg, &err);
switch(i)
{
break;
case 't':
- i = atoi(optarg);
+ i = getNum(optarg, &err);
if ((i >= PI_CLOCK_PWM) && (i <= PI_CLOCK_PCM))
clockPeripheral = i;
else fatal("invalid -t option (%d)", i);
break;
case 'x':
- mask = strtoll(optarg, &endptr, 0);
- if (!*endptr)
+ mask = getNum(optarg, &err);
+ if (!err)
{
updateMask = mask;
updateMaskSet = 1;
if (updateMaskSet) gpioCfgPermissions(updateMask);
+ gpioCfgSetInternals(cfgInternals);
+
/* start library */
if (gpioInitialise()< 0) fatal("Can't initialise pigpio library");
.br
.br
-Name Cmd & Data Meaning
+Name Cmd & Data Meaning
.br
-Loop Start 255 0 Identify start of a wave block
+Loop Start 255 0 Identify start of a wave block
.br
-Loop Repeat 255 1 x y loop x + y*256 times
+Loop Repeat 255 1 x y loop x + y*256 times
.br
-Delay 255 2 x y delay x + y*256 microseconds
+Delay 255 2 x y delay x + y*256 microseconds
.br
+Loop Forever 255 3 loop forever
+
+.br
+
+.br
+
+.br
+If present Loop Forever must be the last entry in the chain.
.br
For more information, please refer to <http://unlicense.org/>
*/
-/* PIGPIOD_IF_VERSION 18 */
+/* PIGPIOD_IF_VERSION 19 */
#include <stdio.h>
#include <stdlib.h>
static int gPigNotify = -1;
static uint32_t gNotifyBits;
+static uint32_t gLastLevel;
callback_t *gCallBackFirst = 0;
callback_t *gCallBackLast = 0;
static void dispatch_notification(gpioReport_t *r)
{
- static uint32_t lastLevel = 0;
-
callback_t *p;
uint32_t changed;
int l, g;
if (r->flags == 0)
{
- changed = (r->level ^ lastLevel) & gNotifyBits;
+ changed = (r->level ^ gLastLevel) & gNotifyBits;
- lastLevel = r->level;
+ gLastLevel = r->level;
p = gCallBackFirst;
{
pthread_cancel(*pth);
pthread_join(*pth, NULL);
+ free(pth);
}
}
if (gPigHandle < 0) return pigif_bad_noib;
else
{
+ gLastLevel = read_bank_1();
+
pthNotify = start_thread(pthNotifyThread, 0);
if (pthNotify)
{
return triggered;
}
+
#include "pigpio.h"
-#define PIGPIOD_IF_VERSION 18
+#define PIGPIOD_IF_VERSION 20
/*TEXT
typedef struct callback_s callback_t;
-#define RISING_EDGE 0
-#define FALLING_EDGE 1
-#define EITHER_EDGE 2
-
/*F*/
double time_time(void);
/*D
The following command codes are supported:
-Name @ Cmd & Data @ Meaning
-Loop Start @ 255 0 @ Identify start of a wave block
-Loop Repeat @ 255 1 x y @ loop x + y*256 times
-Delay @ 255 2 x y @ delay x + y*256 microseconds
+Name @ Cmd & Data @ Meaning
+Loop Start @ 255 0 @ Identify start of a wave block
+Loop Repeat @ 255 1 x y @ loop x + y*256 times
+Delay @ 255 2 x y @ delay x + y*256 microseconds
+Loop Forever @ 255 3 @ loop forever
+
+If present Loop Forever must be the last entry in the chain.
The code is currently dimensioned to support a chain with roughly
600 entries and 20 loop counters.
.br
+.IP "\fBCGI \fP - Configuration get internals"
+.IP "" 4
+This command returns the value of the internal library
+configuration settings.
+
+.br
+
+.IP "\fBCSI v\fP - Configuration set internals"
+.IP "" 4
+This command sets the value of the internal library
+configuration settings to \fBv\fP.
+
+.br
+
.IP "\fBGDC u\fP - Get gpio PWM dutycycle"
.IP "" 4
.br
The invert parameter \fBv\fP is 1 for inverted signal, 0 for normal.
+.br
+
\fBExample\fP
.br
.br
.EX
-Name Cmd & Data Meaning
-Loop Start 255 0 Identify start of a wave block
-Loop Repeat 255 1 x y loop x + y*256 times
-Delay 255 2 x y delay x + y*256 microseconds
+Name Cmd & Data Meaning
+Loop Start 255 0 Identify start of a wave block
+Loop Repeat 255 1 x y loop x + y*256 times
+Delay 255 2 x y delay x + y*256 microseconds
+Loop Forever 255 3 loop forever
.EE
+.br
+If present Loop Forever must be the last entry in the chain.
+
.br
The code is currently dimensioned to support a chain with roughly
600 entries and 20 loop counters.
from distutils.core import setup
setup(name='pigpio',
- version='1.21',
+ version='1.22',
author='joan',
author_email='joan@abyz.co.uk',
maintainer='joan',
t9cb = pi.callback(GPIO)
+ old_exceptions = pigpio.exceptions
+
+ pigpio.exceptions = False
+
s = pi.store_script(script)
# Ensure the script has finished initing.
while True:
- time.sleep(0.1)
e, p = pi.script_status(s)
if e != pigpio.PI_SCRIPT_INITING:
break
+ time.sleep(0.1)
oc = t9cb.tally()
pi.run_script(s, [99, GPIO])
- time.sleep(2)
+ while True:
+ e, p = pi.script_status(s)
+ if e != pigpio.PI_SCRIPT_RUNNING:
+ break
+ time.sleep(0.1)
+ time.sleep(0.3)
c = t9cb.tally() - oc
CHECK(9, 1, c, 100, 0, "store/run script")
e, p = pi.script_status(s)
if e != pigpio.PI_SCRIPT_RUNNING:
break
- time.sleep(0.5)
+ time.sleep(0.1)
+ time.sleep(0.3)
c = t9cb.tally() - oc
- time.sleep(0.1)
CHECK(9, 2, c, 201, 0, "run script/script status")
oc = t9cb.tally()
if p[9] < 1900:
pi.stop_script(s)
time.sleep(0.1)
+ time.sleep(0.3)
c = t9cb.tally() - oc
- time.sleep(0.1)
- CHECK(9, 3, c, 110, 10, "run/stop script/script status")
+ CHECK(9, 3, c, 110, 20, "run/stop script/script status")
e = pi.delete_script(s)
CHECK(9, 4, e, 0, 0, "delete script")
+ pigpio.exceptions = old_exceptions
+
def ta():
print("Serial link tests.")
oc = t5_count;
time_sleep(5.05);
c = t5_count - oc;
- CHECK(5, 4, c, 50, 1, "callback");
+ CHECK(5, 4, c, 50, 2, "callback");
e = wave_tx_stop();
CHECK(5, 5, e, 0, 0, "wave tx stop");
if [[ $s = "" ]]; then echo "BS2 ok"; else echo "BS2 fail ($s)"; fi
s=$(pigs h)
-if [[ ${#s} = 4321 ]]; then echo "HELP ok"; else echo "HELP fail (${#s})"; fi
+if [[ ${#s} = 4412 ]]; then echo "HELP ok"; else echo "HELP fail (${#s})"; fi
s=$(pigs hwver)
if [[ $s -ne 0 ]]; then echo "HWVER ok"; else echo "HWVER fail ($s)"; fi